package net.socket.server;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import net.socket.server.message.MessageManager;
import net.socket.server.protocal.PROTOID;
import net.socket.server.request.IRequest;
import observable.subject.MessageCenter;
import util.MyFactory;

public class SocketServer extends Thread {
	
	public void run() {
		try {
			startServer();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	//public final static String adress = "14.119.109.232";
	//测试环境
	public final static String adress = "192.168.0.205";
	private int port = 8081;
	
	private void heartBeat(){
		try {
			MessageCenter mc = MyFactory.context.getBean("MessageCenter", MessageCenter.class);
			mc.distribute(PROTOID.HEART_BEAT_ONE_TENTH_SECOND, new IRequest());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private static final EventExecutorGroup executorGroup = new DefaultEventExecutorGroup(1);
	 private void startServer() throws Exception {
	        EventLoopGroup bossGroup = new NioEventLoopGroup(1);//包含一个线程组，处理网络事件，（reactor线程组）
	        EventLoopGroup workerGroup = new NioEventLoopGroup(1);//处理SocketChannel的网络读写
	        executorGroup.scheduleAtFixedRate(()->heartBeat(), 0, 100, TimeUnit.MILLISECONDS);
	        
	        try {
	            ServerBootstrap b = new ServerBootstrap();//netty用于启动nio服务端的辅助启动类
	            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)//group,将两个nio线程组传入ServerBootstrap；channel对应jdk的ServerSocketChannel
	                .childHandler(new ChannelInitializer<SocketChannel>() {//处理i/o事件类似于reactor中的handler
	                    @Override
	                    public void initChannel(SocketChannel ch) throws Exception {
	                        ch.pipeline().addLast("socket-decoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, -4, 4));
	                        ch.pipeline().addLast(executorGroup, MyFactory.context.getBean("SocketServerInboundHandler",SocketServerInboundHandler.class));
	                }
	            }).option(ChannelOption.SO_BACKLOG, 1024) //配置tcp参数，将backlog设置成1024
	            .childOption(ChannelOption.SO_KEEPALIVE, true);//长连接,设置tcp协议栈会自动发送keeplive探测包
	        ChannelFuture f = b.bind(adress,port).sync();//绑定监听端口，调用同步阻塞方法sync等待绑定操作完成，完成后返回一个ChannelFuture，用于异步操作的通知回调
	        f.channel().closeFuture().sync();//等待服务器监听端口关闭才退出
	    } finally {
	        workerGroup.shutdownGracefully();//退出，释放线程池资源
	        bossGroup.shutdownGracefully();
	    }
}
}
